use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{Write};
use std::path::{Path, PathBuf};
use anyhow::Result;
use log::{debug, info};

use crate::project::Project;
use crate::sln_parser::Solution;

/// Represents a CMake project
pub struct CMakeProject {
    pub name: String,
    pub root_dir: PathBuf,
    pub source_files: Vec<PathBuf>,
    pub header_files: Vec<PathBuf>,
    pub include_dirs: Vec<PathBuf>,
    pub lib_dirs: Vec<PathBuf>,
    pub libraries: Vec<String>,
    pub preprocessor_defs: HashMap<String, Vec<String>>,    pub dependencies: Vec<String>,
    pub _is_executable: bool,
    pub qt_modules: Vec<String>,
    pub qt_dir: Option<String>,
    pub resources: Vec<String>,  // Qt resource files (.qrc)
    pub forms: Vec<String>,      // Qt UI files (.ui)
}

impl CMakeProject {
    /// 从Project对象创建CMakeProject
    pub fn from_project(project: &Project, _project_path: &Path, output_dir: &Path, qt_dir: Option<String>) -> Result<Self> {
        let project_dir = output_dir.join(&project.name);
        
        // 将字符串路径转换为PathBuf
        let source_files: Vec<PathBuf> = project.source_files.iter()
            .map(|path| PathBuf::from(path))
            .collect();
            
        let header_files: Vec<PathBuf> = project.header_files.iter()
            .map(|path| PathBuf::from(path))
            .collect();
            
        // 将包含目录从HashMap<String, Vec<String>>转换为Vec<PathBuf>
        // 使用HashSet去重，确保没有重复的目录
        let mut include_dirs_set = std::collections::HashSet::new();
        for dirs in project.include_directories.values() {
            for dir in dirs {
                include_dirs_set.insert(dir.clone());
            }
        }
        
        let include_dirs: Vec<PathBuf> = include_dirs_set.into_iter()
            .map(|dir| PathBuf::from(dir))
            .collect();
            
        // 创建一个空的库目录列表，因为Project中没有此信息
        let lib_dirs: Vec<PathBuf> = Vec::new();
        
        Ok(CMakeProject {
            name: project.name.clone(),
            root_dir: project_dir,
            source_files,
            header_files,
            include_dirs,
            lib_dirs,
            libraries: project.libraries.clone(),
            preprocessor_defs: project.preprocessor_defs.clone(),            dependencies: project.dependencies.clone(),
            _is_executable: true,
            qt_modules: project.qt_modules.clone(),
            qt_dir,
            resources: project.resources.clone(),
            forms: project.forms.clone(),
        })
    }
    
    /// Generates the CMakeLists.txt file for this project
    pub fn generate_cmake_file(&self) -> Result<()> {
        info!("Generating CMakeLists.txt for project: {}", self.name);
        
        // Create output directory if it doesn't exist
        fs::create_dir_all(&self.root_dir)?;
        
        let cmake_path = self.root_dir.join("CMakeLists.txt");
        let mut file = File::create(&cmake_path)?;
        
        // Write CMake minimum version
        writeln!(file, "cmake_minimum_required(VERSION 3.14)")?;
        writeln!(file, "")?;
        
        // Write project definition
        writeln!(file, "project({} LANGUAGES CXX)", self.name)?;
        writeln!(file, "")?;
        
        // Set C++ standard
        writeln!(file, "set(CMAKE_CXX_STANDARD 17)")?;
        writeln!(file, "set(CMAKE_CXX_STANDARD_REQUIRED ON)")?;
        writeln!(file, "")?;
        
        // Add Qt support if Qt modules are present
        if !self.qt_modules.is_empty() {
            writeln!(file, "# Qt support")?;
            writeln!(file, "set(CMAKE_AUTOMOC ON)")?;
            writeln!(file, "set(CMAKE_AUTORCC ON)")?;
            writeln!(file, "set(CMAKE_AUTOUIC ON)")?;
            writeln!(file, "")?;
            
            // Add Qt path configuration if provided
            if let Some(qt_dir) = &self.qt_dir {
                writeln!(file, "# Qt path configuration")?;
                writeln!(file, "set(QT_DIR \"{}\" CACHE PATH \"Qt安装目录路径\")", qt_dir)?;
                writeln!(file, "list(APPEND CMAKE_PREFIX_PATH \"${{QT_DIR}}\")")?;
                writeln!(file, "")?;
            }
            
            // Add Qt modules
            writeln!(file, "find_package(Qt5 COMPONENTS {})", self.qt_modules.join(" "))?;
            writeln!(file, "")?;
        }
        
        // Add source files
        writeln!(file, "# Source files")?;
        writeln!(file, "set(SOURCES")?;
        for source in &self.source_files {
            writeln!(file, "    {}", self.get_cmake_path(source))?;
        }
        writeln!(file, ")")?;
        writeln!(file, "")?;

        // Add header files
        writeln!(file, "# Header files")?;
        writeln!(file, "set(HEADERS")?;
        for header in &self.header_files {
            writeln!(file, "    {}", self.get_cmake_path(header))?;
        }
        writeln!(file, ")")?;
        writeln!(file, "")?;

        // Add Qt resource files
        if !self.qt_modules.is_empty() {
            writeln!(file, "# Qt resource files")?;
            writeln!(file, "set(RESOURCES")?;
            for resource in &self.resources {
                writeln!(file, "    {}", resource)?;
            }
            writeln!(file, ")")?;
            writeln!(file, "")?;

            // Add Qt UI files
            writeln!(file, "# Qt UI files")?;
            writeln!(file, "set(FORMS")?;
            for form in &self.forms {
                writeln!(file, "    {}", form)?;
            }
            writeln!(file, ")")?;
            writeln!(file, "")?;
        }

        // Add executable target
        writeln!(file, "add_executable(${{PROJECT_NAME}} ${{SOURCES}} ${{HEADERS}}")?;
        if !self.qt_modules.is_empty() {
            writeln!(file, "    ${{RESOURCES}} ${{FORMS}}")?;
        }
        writeln!(file, ")")?;
        writeln!(file, "")?;
        
        // Add include directories
        if !self.include_dirs.is_empty() {
            writeln!(file, "target_include_directories(${{PROJECT_NAME}} PRIVATE")?;
            for include_dir in &self.include_dirs {
                writeln!(file, "    {}", self.get_cmake_path(include_dir))?;
            }
            writeln!(file, ")")?;
            writeln!(file, "")?;
        }
        
        // Add library directories
        if !self.lib_dirs.is_empty() {
            writeln!(file, "target_link_directories(${{PROJECT_NAME}} PRIVATE")?;
            for lib_dir in &self.lib_dirs {
                writeln!(file, "    {}", self.get_cmake_path(lib_dir))?;
            }
            writeln!(file, ")")?;
            writeln!(file, "")?;
        }
        
        // Add libraries
        if !self.libraries.is_empty() {
            writeln!(file, "target_link_libraries(${{PROJECT_NAME}} PRIVATE")?;
            for lib in &self.libraries {
                writeln!(file, "    {}", lib)?;
            }
            writeln!(file, ")")?;
            writeln!(file, "")?;
        }
        
        // Add Qt libraries if Qt modules are present
        if !self.qt_modules.is_empty() {
            writeln!(file, "# Qt libraries")?;
            writeln!(file, "target_link_libraries(${{PROJECT_NAME}} PRIVATE")?;
            for module in &self.qt_modules {
                //module 的首字母要大写
                let mut chars = module.chars();
                let formatted_module = match chars.next() {
                    Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
                    None => String::new(),
                };
                writeln!(file, "    Qt5::{}", formatted_module)?;
            }
            writeln!(file, ")")?;
            writeln!(file, "")?;
        }
        
        // Add preprocessor definitions
        if !self.preprocessor_defs.is_empty() {
            writeln!(file, "# Preprocessor definitions")?;
            for (_config, defs) in &self.preprocessor_defs {
                if !defs.is_empty() {
                    writeln!(file, "target_compile_definitions(${{PROJECT_NAME}} PRIVATE")?;
                    for def in defs {
                        writeln!(file, "    {}", def)?;
                    }
                    writeln!(file, ")")?;
                }
            }
            writeln!(file, "")?;
        }
        
        // Add dependencies
        if !self.dependencies.is_empty() {
            writeln!(file, "# Dependencies")?;
            for dep in &self.dependencies {
                writeln!(file, "add_dependencies(${{PROJECT_NAME}} {})", dep)?;
            }
            writeln!(file, "")?;
        }
        
        debug!("CMakeLists.txt generated at: {}", cmake_path.display());
        
        Ok(())
    }
    
    /// Generates a path suitable for CMake (using forward slashes)
    fn get_cmake_path(&self, path: &Path) -> String {
        // 保留完整路径而不仅仅是文件名
        // 将路径转换为CMake格式（使用正斜杠）
        path.to_string_lossy().replace('\\', "/")
    }
}

/// 为解决方案生成根CMakeLists.txt文件
pub fn generate_root_cmake(solution: &Solution, output_dir: &Path) -> Result<()> {
    info!("Generating root CMakeLists.txt for solution: {}", solution.solution_name);
    
    let cmake_path = output_dir.join("CMakeLists.txt");
    let mut file = File::create(&cmake_path)?;
    
    // Write CMake minimum version
    writeln!(file, "cmake_minimum_required(VERSION 3.14)")?;
    writeln!(file, "")?;
    
    // Write project definition
    writeln!(file, "project({} LANGUAGES CXX)", solution.solution_name)?;
    writeln!(file, "")?;
    
    // Set C++ standard
    writeln!(file, "set(CMAKE_CXX_STANDARD 17)")?;
    writeln!(file, "set(CMAKE_CXX_STANDARD_REQUIRED ON)")?;
    writeln!(file, "")?;
    
    // Add all projects as subdirectories
    writeln!(file, "# Add all projects")?;
    for project in &solution.projects {
        writeln!(file, "add_subdirectory({})", project.name)?;
    }
    
    info!("Successfully generated root CMakeLists.txt");
    Ok(())
} 